package com.hippoDocker.security.config;

import com.hippoDocker.security.filter.JwtAuthenticationTokenfilter;
import com.hippoDocker.security.handler.AuthenticationEntryPointImpl;
import com.hippoDocker.security.handler.AccessDenieHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * @ClassName SecurityConfig
 * @Description TODO SpringSecurity配置类
 * @Author tangxl
 * @Date 2022/7/26 18:53
 **/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法权限验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationTokenfilter jwtAuthenticationTokenfilter;
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPointImpl;
    @Autowired
    private AccessDenieHandlerImpl accessDenieHandlerImpl;


    /**
     * 密码加密存储：security默认加密为PasswordEncoder，修改为BCryptPasswordEncoder
     * 创建BCryptPasswordEncoder注入容器
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 重写configure方法，接口放行操作
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 开启跨域访问
        http.cors().configurationSource(CorsConfigurationSource());
        // 开启模拟请求，比如API POST测试工具的测试，不开启时，API POST为报403错误
        http.
                //关闭csrf,本次采用的 JWT
                csrf().disable()
                //不通过Session获取SecurityContext;SessionCreationPolicy.STATELESS不创建httpSession对象
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //对于登录接口 运行匿名访问
                .antMatchers("/umsMember/login").anonymous()
                //对接口 /testCors 设置权限
                .antMatchers("/testCors").hasAuthority("pms:product:read")
                //不拦截 /webjars 开放的资源
                .antMatchers("/webjars/**").permitAll()
                //不限定静态资源
                .antMatchers("/**/*.html","/**/*.js","/**/*.css").permitAll()
                //不限定swagger资源
                .antMatchers("/doc.html","/swagger-resources").permitAll()
                //除去上面所有请求都需要鉴权认证
                .anyRequest().authenticated();

        //将自定义的JwtAuthenticationTokenfilter过滤器添加到Security过滤器链的UsernamePasswordAuthenticationFilter过滤器之前
        http.addFilterBefore(jwtAuthenticationTokenfilter,UsernamePasswordAuthenticationFilter.class);
        //配置异常处理器
        http.exceptionHandling()
                //配置认证失败处理器
                .authenticationEntryPoint(authenticationEntryPointImpl)
                //配置授权失败处理器
                .accessDeniedHandler(accessDenieHandlerImpl);
    }

    /**
     * 创建跨域配置
     * @return
     */
    private CorsConfigurationSource CorsConfigurationSource() {
        CorsConfigurationSource source =   new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");	//同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
        corsConfiguration.addAllowedHeader("*");    //header，允许哪些header，本案中使用的是token，此处可将*替换为token；
        corsConfiguration.addAllowedMethod("*");	//允许的请求方法，PSOT、GET等
        ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**",corsConfiguration); //配置允许跨域访问的url
        return source;
    }

    /**
     * AuthenticationManager注入spring，用于用户认证
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
